package com.simons.common.ftp.factory;

import java.io.IOException;
import java.net.SocketException;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import com.simons.common.ftp.simple.ConnectParam;
import com.simons.common.utils.PoolUtil;

import lombok.Getter;
import lombok.extern.log4j.Log4j2;

@Log4j2
public class PoolFtpClientFactory implements PooledObjectFactory<FtpClientPool>{

	@Getter
	private GenericObjectPool<FtpClientPool> objectPool;  
	
	private static final String CUR_POOL_NAME = "PoolFtpClient";
	
	private ConnectParam connectParam;
	
	public PoolFtpClientFactory(ConnectParam connectParam){
		try {
			GenericObjectPoolConfig poolConfig = PoolUtil.getGenericObjectPoolConfig();
			objectPool = new GenericObjectPool<FtpClientPool>(this, poolConfig);
			this.connectParam = connectParam;
		} catch (Exception e) {
			log.error("", e);
		}
	}
	
	/**
	 * 开启链接
	 */
	private FTPClient connect() throws SocketException, IOException {
		if (connectParam == null) {
			return null;
		}

		FTPClient ftpClient = new FTPClient();
		ftpClient.connect(connectParam.getHost(), connectParam.getPort());
		ftpClient.login(connectParam.getUsername(), connectParam.getPassword());

		int reply = ftpClient.getReplyCode();
		
		boolean success = FTPReply.isPositiveCompletion(reply);

		if(success){
			return ftpClient;
		}
		return null;
	}
	
	/**
	 * 关闭链接
	 */
	private void closeConnect(FTPClient ftpClient) throws IOException {
		try {
			ftpClient.logout();
		} catch (Exception e) {
            log.error("", e);
		} finally {
			try {
                ftpClient.disconnect();
           } catch (Exception e) {
                log.error("", e);
           }
		}
	}

	
	@Override
	public PooledObject<FtpClientPool> makeObject() throws Exception {
		log.info(CUR_POOL_NAME+" make Object:");
		
		FTPClient ftpClient = connect(); 
		FtpClientPool poolFtpClient = new FtpClientPool(ftpClient, 0, 20);
		return new DefaultPooledObject<FtpClientPool>(poolFtpClient);
	}

	@Override
	public void destroyObject(PooledObject<FtpClientPool> pooledObject) throws Exception {
		 log.info(CUR_POOL_NAME+" destroy Object");
		 FtpClientPool ftpClientPool = pooledObject.getObject();
		 closeConnect( ftpClientPool.getFtpClient() );
		 ftpClientPool = null;
	}

	@Override
	public boolean validateObject(PooledObject<FtpClientPool> pooledObject) {
		// TODO Auto-generated method stub
		log.info(CUR_POOL_NAME+" validate Object");
		
		FtpClientPool ftpClientPool = pooledObject.getObject();
		int curUseTime = ftpClientPool.getCurUseTime();
		curUseTime += 1;
		if(curUseTime > FtpClientPool.MAX_USE_TIME){
			return false;
		}
		ftpClientPool.setCurUseTime(curUseTime);
		
		try {
			return ftpClientPool.getFtpClient().sendNoOp();
		} catch (IOException e) {
			log.error("", e);
		}
		return false;
	}

	@Override
	public void activateObject(PooledObject<FtpClientPool> pooledObject) throws Exception {
		log.info(CUR_POOL_NAME+" activate Object");
		
	}

	@Override
	public void passivateObject(PooledObject<FtpClientPool> pooledObject) throws Exception {
		log.info(CUR_POOL_NAME+" passivate Object");
		
	}
	
	/**
	 * 对象池使用示例，因为该对象池操作比较复杂，如果频率很低的请求可以直接调用simple的ftpOper
	 * 当调用次数比较频繁，而且对项目的性能要求也比较严格的时候才建议使用该方法
	 */
//	public static void main(String[] args) throws Exception {
//		PoolFtpClientFactory poolFtpClientFactory = new PoolFtpClientFactory(new ConnectParam("127.0.0.1", 21, "jsm", "19953y2r"));
//		GenericObjectPool<FtpClientPool> genericObjectPool = poolFtpClientFactory.getObjectPool();
//		FtpClientPool ftpClientPool = genericObjectPool.borrowObject(10000L);
//		FactoryFTPOper factoryFTPOper = new FactoryFTPOper(ftpClientPool.getFtpClient());
//		System.out.println(factoryFTPOper.readFtpToString("/20170825", "data.txt"));
//		genericObjectPool.returnObject(ftpClientPool);
//	}

}
